#ifndef __OMODEL_DEF_H__
#define __OMODEL_DEF_H__

#include "model/oModel.h"

class oAnimateTo;
class oSequence;
class oFrameActionDef;

/** @brief Clips are different rectangle areas on textures.
 This is the data for clips from a single texture.
*/
class oDLL oClipDef: public CCObject
{
public:
	/** The only method to create a clip define. */
	static oClipDef* create();
	/** Name of the texture file. Name only, not file path. */
	string textureFile;
	/** Different areas on this texture. */
	ptr_vector<CCRect> rects;
	/** Get a sprite instance with an area index. */
	CCSprite* toSprite(uint32 index);
	string toXml();
protected:
	oClipDef();
};

/** @brief Interface for data define of oActionInterval. */
class oDLL oActionDef
{
public:
	virtual ~oActionDef(){}
	virtual oSequence* toAction() = 0;
	virtual string toXml() = 0;
};

/** @brief Define for a model`s single animation frame.
 A model`s animation consists of a sequence of animation frames.
 It`s component class of oAniamtionDef. Do not use it alone.
*/
class oKeyFrameDef
{
public:
	oKeyFrameDef(
		float duration,
		float x,
		float y,
		float rotation,
		float scaleX,
		float scaleY,
		GLubyte opacity);
	int easePos;
	int easeScale;
	int easeRotate;
	int easeOpacity;
	oAnimateTo* toAction();
	string toXml();
private:
	float _duration;
	float _x;
	float _y;
	float _rotation;
	float _scaleX;
	float _scaleY;
	GLubyte _opacity;
};

/** @brief Data define for animation of model node.
 It implements interface oActionDef. 
 It`s component class of oSpriteDef. Do not use it alone.
*/
class oAnimationDef: public oActionDef
{
public:
	void add(oKeyFrameDef* def);
	virtual oSequence* toAction();
	virtual string toXml();
private:
	ptr_vector<oKeyFrameDef> _frames;
};

/** @brief The frame animation define for model.
 It implements interface oActionDef. 
 It`s component class of oSpriteDef. Do not use it alone.
*/
class oFrameAnimationDef: public oActionDef
{
public:
	oFrameAnimationDef(const char* frameFile, float begin, float end);
	virtual ~oFrameAnimationDef();
	virtual oSequence* toAction();
	virtual string toXml();
private:
	oFrameActionDef* _def;
	string _frameFile;
	float _begin;
	float _end;
};

/** @brief It`s component class of oModelDef. Do not use it alone. */
class oSpriteDef
{
public:
	oSpriteDef(CCTexture2D* tex,
		float x,
		float y,
		float scaleX,
		float scaleY,
		float rotation,
		float archorX,
		float archorY,
		const CCRect& rect,
		int clip = -1,
		GLubyte opacity = 255);
	~oSpriteDef();

	void addChild(oSpriteDef* def);

	void addAction(oActionDef* def);
	oActionDef* getAction(uint32 index);
	uint32 actionSize();

	void addLook(uint32 look);
	int getLook(uint32 index);
	uint32 lookSize();

	const vector<oSpriteDef*>& children();

	void restore(CCSprite* sprite);
	CCSprite* toSprite();
	string toXml();

	oAnimateTo* toResetAction();

	template<typename NodeFunc>
	static void traverse(oSpriteDef* root, const NodeFunc& func)
	{
		func(root);
		const vector<oSpriteDef*>& childrenDef = root->children();
		BOOST_FOREACH(oSpriteDef* childDef, childrenDef)
		{
			oSpriteDef::traverse(childDef, func);
		}
	}
private:
	vector<oSpriteDef*> _children;
	vector<oActionDef*> _actions;
	vector<uint32> _looks;
	int _clip;
	float _x;
	float _y;
	float _rotation;
	float _archorX;
	float _archorY;
	float _scaleX;
	float _scaleY;
	GLubyte _opacity;
	CCTexture2D* _texture;
	CCRect _rect;
};

/** @brief Data define for a 2D model. */
class oDLL oModelDef: public CCObject
{
public:
	enum {BulletKey = 0, AttackKey, HitKey, OriginKey};
	oModelDef();
	~oModelDef();
	CCTexture2D* getTexture();
	oSpriteDef* getRoot();
	void addKeyPoint(const CCPoint& point);
	const CCPoint& getKeyPoint(uint32 index) const;
	bool isFaceRight() const;
	void setActionName(int index, const string& name);
	void setLookName(int index, const string& name);
	int getActionIndexByName(const string& name);
	int getLookIndexByName(const string& name);
	oModel* toModel();
	string toXml();
private:
	typedef hash_strmap<int> oIndexMap;
	void setTexture(CCTexture2D* tex);
	void setRoot(oSpriteDef* root);
	void visit(oSpriteDef* parentDef, CCNode* parentNode);
	bool _isFaceRight;
	ptr_vector<CCPoint> _keys;
	CCTexture2D* _texture;
	oSpriteDef* _root;
	oModel* _pModel;
	string _clip;
	oIndexMap _actionIndex;
	oIndexMap _lookIndex;
	friend class oModelCache;
};

#endif